package com.shanshan.crowd.mvc.config;

import com.google.gson.Gson;
import com.shanshan.crowd.constant.CrowdConstant;
import com.shanshan.crowd.exception.AccessForbiddenException;
import com.shanshan.crowd.exception.LoginAcctAlreadyInUpdateException;
import com.shanshan.crowd.exception.LoginAcctAlreadyInUseException;
import com.shanshan.crowd.exception.LoginFailedException;
import com.shanshan.crowd.util.CrowdUtil;
import com.shanshan.crowd.util.ResultEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

/**
 * @Description
 * @ClassName CrowdExceptionResolver
 * @Author 山山大魔王
 * @Date 2022/7/20 19:57
 * @Version 1.0
 */
@ControllerAdvice
public class CrowdExceptionResolver {

    @ExceptionHandler(value = LoginAcctAlreadyInUpdateException.class)
    public ModelAndView resolveLoginAcctAlreadyInUpdateException(
            LoginAcctAlreadyInUseException exception,
            HttpServletRequest request,
            HttpServletResponse response

    ) throws IOException {
        ExecutorService ex= Executors.newFixedThreadPool(5);
        String viewName = "system-error";
        return commonResolveException(exception, request, response, viewName);
    }

    @ExceptionHandler(value = LoginAcctAlreadyInUseException.class)
    public ModelAndView resolveLoginAcctAlreadyInUseException(
            LoginAcctAlreadyInUseException exception,
            HttpServletRequest request,
            HttpServletResponse response
    ) throws IOException {
        String viewName = "admin-add";
        return commonResolveException(exception, request, response, viewName);
    }

    //没有登录
    @ExceptionHandler(value = AccessForbiddenException.class)
    public ModelAndView resolveAccessForbiddenException(
            Exception exception,
            HttpServletRequest request,
            HttpServletResponse response
    ) throws IOException {
        String viewName = "admin-login";

        return commonResolveException(exception, request, response, viewName);
    }

    //登录信息
    @ExceptionHandler(value = LoginFailedException.class)
    public ModelAndView resolveLoginFailedException(
            Exception exception,
            HttpServletRequest request,
            HttpServletResponse response
    ) throws IOException {
        String viewName = "admin-login";

        return commonResolveException(exception, request, response, viewName);
    }

    //异常兜底异常
    @ExceptionHandler(value = Exception.class)
    public ModelAndView resolveException(
            Exception exception,
            HttpServletRequest request,
            HttpServletResponse response
    ) throws IOException {
        String viewName = "system-error";

        return commonResolveException(exception, request, response, viewName);
    }

    /**
     * 核心异常处理方法
     * @param exception SpringMVC捕获到的异常
     * @param request 为了判断当前请求是“普通请求”还是ajax请求需要传入原生request对象
     * @param response 为了能够将JSON字符串作为当前请求的响应数据返回给浏览器
     * @param viewName 指定要前往的视图名称
     * @return
     * @throws IOException
     */
    private ModelAndView commonResolveException(
            Exception exception,
            HttpServletRequest request,
            HttpServletResponse response,
            String viewName
    ) throws IOException {
        // 1.判断当前请求是普通请求还是ajax请求
        boolean judgeResult = CrowdUtil.judgeRequestType(request);

        // 2.如果是Ajax请求
        if (judgeResult){
            // 3.从当前异常对象中获取异常信息
            String message = exception.getMessage();

            // 4.创建ResultEntity
            ResultEntity<Object> resultEntity = ResultEntity.failed(message);

            // 5.创建Gson对象
            Gson gson = new Gson();

            // 6.将resultEntity转化为JSON字符串
            String json = gson.toJson(resultEntity);

            // 7.把当前JSON字符串作为当前请求的响应体数据返回给浏览器
            // ①获取writer对象
            PrintWriter writer = response.getWriter();

            // ②写入数据
            writer.write(json);

            // 8.返回null，不给springmvc提供ModelAndView对象
            // 这样SpringMVC就知道不需要框架解析视图来提供响应，而是程序员自己提供了响应
            return null;
        }

        // 9.创建ModelAndView对象
        ModelAndView modelAndView = new ModelAndView();

        // 10.将Exception对象存入模型
        modelAndView.addObject(CrowdConstant.ATTR_NAME_EXCEPTION,exception);

        // 11.设置目标视图
        modelAndView.setViewName(viewName);

        // 12.返回ModelAndView对象
        return modelAndView;

    }
}
